package com.example.demo.scheduledtask;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.example.demo.mapper.PoMpsinfoMapper;
import com.example.demo.vo.PoMpsinfoVo;
import com.example.demo.vo.PurchaseSupplyMaterialVo;
import com.example.demo.vo.PurchaseSupplyVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.xml.soap.*;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 *
 */
@Component
@Slf4j
@DS("mes")
public class ApsPurchaseSupplyBackfillScheduledTask {
    @Autowired
    PoMpsinfoMapper poMpsinfoMapper;

    /**
     * 请购申请回填，每分钟执行一次
     */
    @Scheduled(cron = "0 0/1 * * * ?")
    @Async(value = "taskExecutor")
    public void purchaseSupplyBackfillScheduledTask() {
        List<PoMpsinfoVo> poMpsinfoVoList = poMpsinfoMapper.getPoMpsinfoVoListFromPrePurchase();  //从请购预处理记录里取请购需求
        if(poMpsinfoVoList == null || poMpsinfoVoList.size() == 0){
            return;
        }

        //根据是否为样机需求拆分为两个数据组(获取样机相关需求)
        List<PoMpsinfoVo> poMpsinfoVoListWithPrototype = poMpsinfoVoList.stream().filter(p->p.getIsPrototype() == 1).collect(Collectors.toList());

        //根据是否为样机需求拆分为两个数据组(获取非样机相关需求)
        List<PoMpsinfoVo> poMpsinfoVoListWithNonPrototype = poMpsinfoVoList.stream().filter(p->p.getIsPrototype() == 0).collect(Collectors.toList());

        //处理样机物需
        PurchaseSupplyVo purchaseSupplyReq = new PurchaseSupplyVo();
        List<PurchaseSupplyMaterialVo> purchaseSupplyMaterialReqs = new ArrayList<>();
        if(poMpsinfoVoListWithPrototype != null && poMpsinfoVoListWithPrototype.size() > 0){
            //添加采购主表
            purchaseSupplyReq.setActionType("I");
            purchaseSupplyReq.setPmdadocdt(String.format("%tF",new Date()));
            purchaseSupplyReq.setPmda020("Y");
            purchaseSupplyReq.setPmda007("AMA12");
            purchaseSupplyReq.setPmda002("A1909040");
            purchaseSupplyReq.setPmda022("APS下推5113样机需求");
            purchaseSupplyReq.setPmda200("9");
            purchaseSupplyReq.setPmdasite("AMA");
            purchaseSupplyReq.setPmdaud001("APS-"+System.currentTimeMillis());
            purchaseSupplyReq.setPmdadocno("3101");

            for(PoMpsinfoVo poMpsinfoVo : poMpsinfoVoListWithPrototype){
                //添加采购附表
                PurchaseSupplyMaterialVo purchaseSupplyMaterialVo = new PurchaseSupplyMaterialVo();
                purchaseSupplyMaterialVo.setPmdb004(poMpsinfoVo.getMcode());
                purchaseSupplyMaterialVo.setPmdb030(String.format("%tF",poMpsinfoVo.getStartTime()));
                purchaseSupplyMaterialVo.setPmdb007(poMpsinfoVo.getUnits());
                purchaseSupplyMaterialVo.setPmdb006(poMpsinfoVo.getCalnum());
                purchaseSupplyMaterialReqs.add(purchaseSupplyMaterialVo);
            }

            //发送SOAP回填
            startPurchaseSupplyBackFill(purchaseSupplyReq, purchaseSupplyMaterialReqs,1);
        }

        //处理非样机物需
        purchaseSupplyReq = new PurchaseSupplyVo();
        purchaseSupplyMaterialReqs = new ArrayList<>();
        if(poMpsinfoVoListWithNonPrototype != null && poMpsinfoVoListWithNonPrototype.size() > 0) {
            //添加采购主表
            purchaseSupplyReq.setActionType("I");
            purchaseSupplyReq.setPmdadocdt(String.format("%tF", new Date()));
            purchaseSupplyReq.setPmda020("Y");
            purchaseSupplyReq.setPmda007("AMA12");
            purchaseSupplyReq.setPmda002("A1909040");
            purchaseSupplyReq.setPmda022("APS下推需求");
            purchaseSupplyReq.setPmda200("9");
            purchaseSupplyReq.setPmdasite("AMA");
            purchaseSupplyReq.setPmdaud001("APS-" + System.currentTimeMillis());
            purchaseSupplyReq.setPmdadocno("3101");

            for (PoMpsinfoVo poMpsinfoVo : poMpsinfoVoListWithNonPrototype) {
                //添加采购附表
                PurchaseSupplyMaterialVo purchaseSupplyMaterialVo = new PurchaseSupplyMaterialVo();
                purchaseSupplyMaterialVo.setPmdb004(poMpsinfoVo.getMcode());
                purchaseSupplyMaterialVo.setPmdb030(String.format("%tF", poMpsinfoVo.getStartTime()));
                purchaseSupplyMaterialVo.setPmdb007(poMpsinfoVo.getUnits());
                purchaseSupplyMaterialVo.setPmdb006(poMpsinfoVo.getCalnum());
                purchaseSupplyMaterialReqs.add(purchaseSupplyMaterialVo);
            }

            //发送SOAP回填
            startPurchaseSupplyBackFill(purchaseSupplyReq, purchaseSupplyMaterialReqs,0);
        }
    }

    private void startPurchaseSupplyBackFill(PurchaseSupplyVo purchaseSupplyReq, List<PurchaseSupplyMaterialVo> purchaseSupplyMaterialReqs, Integer isPrototype) {
        //获取xml格式参数
        String resMessage = getSoapXml(purchaseSupplyReq, purchaseSupplyMaterialReqs);

        try {
            //转换为soap消息
            MessageFactory msgFactory = MessageFactory.newInstance();
            SOAPMessage message = msgFactory.createMessage();
            SOAPPart soapPart = message.getSOAPPart();
            byte[] buffer = resMessage.getBytes();
            ByteArrayInputStream stream = new ByteArrayInputStream(buffer);
            StreamSource source = new StreamSource(stream);
            soapPart.setContent(source);
            message.writeTo(System.out);

            //发送soap消息，并解析结果
            String result = sendSoapMessage(message);
            if(result.contains("单据生成成功！")){
                //获取生成的ERP单号
                String billNo = result.substring(result.indexOf("AMA"),result.indexOf("AMA")+18);

                //更新ERP单号
                poMpsinfoMapper.updateErpPurchaseBillByPrototype(isPrototype,billNo);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private String sendSoapMessage(SOAPMessage message) {
        String xmlData = "";
        try {
            // 创建连接
            SOAPConnectionFactory soapConnFactory = SOAPConnectionFactory.newInstance();
            SOAPConnection soapConn = soapConnFactory.createConnection();

            URL url = new URL("http://172.19.255.3/wtoptst/ws/r/awsp900");
            // 响应消息
            SOAPMessage reply = soapConn.call(message, url);
            // 创建soap消息转换对象
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            // 提取消息内容
            Source sourceContent = reply.getSOAPPart().getContent();
            //输出流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            StreamResult result = new StreamResult(out);
            //sourceContent实现此接口的对象包含充当源输入（XML 源或转换指令）所需的信息
            //result充当转换结果的持有者，可以为 XML、纯文本、HTML 或某些其他格式的标记
            transformer.transform(sourceContent, result);
            //返回结果
            xmlData = new String(out.toByteArray());
            //关闭连接
            soapConn.close();
        }catch (Exception e){
            e.printStackTrace();
        }

        return xmlData;
    }

    public <T,K> String getSoapXml(T obj, List<K> objs){
        //正理生能项目回填ERP协议框架
        String start = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:tip=\"http://www.digiwin.com.cn/tiptop/TIPTOPServiceGateWay\">\n" +
                "   <soapenv:Header/>\n" +
                "   <soapenv:Body>\n" +
                "      <tip:invokeSrv>\n" +
                "         <request>&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n" +
                "&lt;request type=\"sync\" key=\"d41d8cd98f00b204e9800998ecf8427e\"&gt;\n" +
                "    &lt;host prod=\"AMA\" ver=\"1.0\" ip=\"10.0.0.1\" id=\"\" lang=\"zh_CN\" timezone=\"+8\" timestamp=\"1658122245035\" acct=\"tiptop\"/&gt;\n" +
                "    &lt;service prod=\"T100\" name=\"PurchaseRequstOrder\" srvver=\"1.0\" ip=\"172.19.255.3\" id=\"toptst\"/&gt;\n" +
                "    &lt;datakey type=\"FOM\"&gt;\n" +
                "        &lt;key name=\"EntId\"&gt;5&lt;/key&gt;\n" +
                "        &lt;key name=\"CompanyId\"&gt;AMA&lt;/key&gt;\n" +
                "    &lt;/datakey&gt;\n" +
                "    &lt;payload&gt;\n" +
                "        &lt;param key=\"data\" type=\"XML\"&gt;\n" +
                "            &lt;![CDATA[\n" +
                "            &lt;Request&gt;\n" +
                "             &lt;RequestContent&gt;\n" +
                "              &lt;Document&gt;\n" +
                "               &lt;RecordSet id='1'&gt;\n" +
                "                &lt;Master name='pmda_t' node_id='1'&gt;";
        String end = "&lt;/Master&gt;\n" +
                "               &lt;/RecordSet&gt;\n" +
                "             &lt;/Document&gt;\n" +
                "           &lt;/RequestContent&gt;\n" +
                "          &lt;/Request&gt;\n" +
                "         ]]&gt;\n" +
                "        &lt;/param&gt;\n" +
                "    &lt;/payload&gt;\n" +
                "&lt;/request&gt;\n" +
                "</request>\n" +
                "      </tip:invokeSrv>\n" +
                "   </soapenv:Body>\n" +
                "</soapenv:Envelope>";

        //组装请购需求主表xml
        String mainTableXml = getXmlFromObject(obj);
        mainTableXml = "\n&lt;Record&gt;\n" + "&lt;Field name='ActionType' value='I'/&gt;\n" +
                mainTableXml + "&lt;/Record&gt;";

        //组装请购需求物料附表xml
        String detailTableXml = "";
        for(K objDetail : objs){
            String temp = getXmlFromObject(objDetail);
            detailTableXml = detailTableXml + "&lt;Record&gt;\n" + temp + "&lt;/Record&gt;\n";
        }

        detailTableXml = "&lt;Detail name='pmdb_t' node_id='1_1'&gt;\n" + detailTableXml + "&lt;/Detail&gt;\n";

        return start+mainTableXml+detailTableXml+end;
    }

    private String getXmlFromObject(Object obj) {
        String result = "";

        Field[] fields = obj.getClass().getDeclaredFields();

        for (Field item : fields) {
            try {
                item.setAccessible(true);
                result = result + "&lt;Field name=" + "'" + item.getName()+ "'" + " value=" + "'" + item.get(obj)  + "'" + "/&gt;\n";
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        return result;
    }
}
